<?php

namespace app\service;

use think\facade\Log;

/**
 * 日志服务类
 */
class LogService
{
    /**
     * 记录API访问日志
     * @param string $message 日志消息
     * @param array $data 数据
     */
    public static function apiAccess(string $message, array $data = []): void
    {
        $logData = array_merge([
            'timestamp' => date('Y-m-d H:i:s'),
            'request_id' => self::getRequestId(),
        ], $data);

        $formattedMessage = self::formatMessage($message, $logData);
        Log::info($formattedMessage);
    }

    /**
     * 记录用户操作日志
     * @param string $message 日志消息
     * @param array $data 数据
     */
    public static function userOperation(string $message, array $data = []): void
    {
        $logData = array_merge([
            'timestamp' => date('Y-m-d H:i:s'),
            'request_id' => self::getRequestId(),
        ], $data);

        $formattedMessage = self::formatMessage($message, $logData);
        Log::info($formattedMessage);
    }

    /**
     * 记录错误日志
     * @param string $message 日志消息
     * @param array $data 数据
     * @param \Exception|null $exception 异常对象
     */
    public static function error(string $message, array $data = [], ?\Exception $exception = null): void
    {
        $logData = array_merge([
            'timestamp' => date('Y-m-d H:i:s'),
            'request_id' => self::getRequestId(),
        ], $data);

        if ($exception) {
            $logData['exception'] = [
                'class' => get_class($exception),
                'message' => $exception->getMessage(),
                'file' => $exception->getFile(),
                'line' => $exception->getLine(),
                'trace' => $exception->getTraceAsString(),
            ];
        }

        $formattedMessage = self::formatMessage($message, $logData);
        Log::error($formattedMessage);
    }

    /**
     * 记录警告日志
     * @param string $message 日志消息
     * @param array $data 数据
     */
    public static function warning(string $message, array $data = []): void
    {
        $logData = array_merge([
            'timestamp' => date('Y-m-d H:i:s'),
            'request_id' => self::getRequestId(),
        ], $data);

        $formattedMessage = self::formatMessage($message, $logData);
        Log::warning($formattedMessage);
    }

    /**
     * 记录调试日志
     * @param string $message 日志消息
     * @param array $data 数据
     */
    public static function debug(string $message, array $data = []): void
    {
        if (!app()->isDebug()) {
            return; // 非调试模式不记录调试日志
        }

        $logData = array_merge([
            'timestamp' => date('Y-m-d H:i:s'),
            'request_id' => self::getRequestId(),
        ], $data);

        $formattedMessage = self::formatMessage($message, $logData);
        Log::debug($formattedMessage);
    }

    /**
     * 记录结构化日志（JSON格式）
     * @param string $message 日志消息
     * @param array $data 数据
     * @param string $level 日志级别
     */
    public static function structured(string $message, array $data = [], string $level = 'info'): void
    {
        $logData = [
            'message' => $message,
            'timestamp' => date('Y-m-d H:i:s'),
            'request_id' => self::getRequestId(),
            'level' => $level,
            'data' => $data,
        ];

        $jsonMessage = json_encode($logData, JSON_UNESCAPED_UNICODE);
        Log::$level($jsonMessage);
    }

    /**
     * 格式化日志消息
     * @param string $message 原始消息
     * @param array $data 数据
     * @return string 格式化后的消息
     */
    private static function formatMessage(string $message, array $data): string
    {
        if (empty($data)) {
            return $message;
        }

        // 将数组数据格式化为可读字符串
        $dataString = self::formatDataString($data);
        return $message . ' | ' . $dataString;
    }

    /**
     * 格式化数据字符串
     * @param array $data 数据
     * @return string 格式化后的字符串
     */
    private static function formatDataString(array $data): string
    {
        $parts = [];
        
        foreach ($data as $key => $value) {
            if (is_array($value) || is_object($value)) {
                $parts[] = $key . '=' . json_encode($value, JSON_UNESCAPED_UNICODE);
            } elseif (is_bool($value)) {
                $parts[] = $key . '=' . ($value ? 'true' : 'false');
            } elseif (is_null($value)) {
                $parts[] = $key . '=null';
            } else {
                $parts[] = $key . '=' . $value;
            }
        }

        return implode(', ', $parts);
    }

    /**
     * 获取请求ID
     * @return string
     */
    private static function getRequestId(): string
    {
        static $requestId = null;
        
        if ($requestId === null) {
            $requestId = uniqid('req_', true);
        }
        
        return $requestId;
    }

    /**
     * 批量记录日志
     * @param array $logs 日志数组 [['level' => 'info', 'message' => '', 'data' => []]]
     */
    public static function batch(array $logs): void
    {
        foreach ($logs as $log) {
            $level = $log['level'] ?? 'info';
            $message = $log['message'] ?? '';
            $data = $log['data'] ?? [];

            switch ($level) {
                case 'error':
                    self::error($message, $data);
                    break;
                case 'warning':
                    self::warning($message, $data);
                    break;
                case 'debug':
                    self::debug($message, $data);
                    break;
                default:
                    self::apiAccess($message, $data);
                    break;
            }
        }
    }

    /**
     * 记录性能日志
     * @param string $operation 操作名称
     * @param float $startTime 开始时间
     * @param array $data 额外数据
     */
    public static function performance(string $operation, float $startTime, array $data = []): void
    {
        $endTime = microtime(true);
        $duration = round(($endTime - $startTime) * 1000, 2); // 转换为毫秒

        $logData = array_merge([
            'operation' => $operation,
            'duration_ms' => $duration,
            'start_time' => date('Y-m-d H:i:s.u', $startTime),
            'end_time' => date('Y-m-d H:i:s.u', $endTime),
        ], $data);

        $level = $duration > 1000 ? 'warning' : 'info'; // 超过1秒记录为警告
        self::structured('性能监控', $logData, $level);
    }

    /**
     * 记录SQL查询日志
     * @param string $sql SQL语句
     * @param array $bindings 绑定参数
     * @param float $time 执行时间（毫秒）
     */
    public static function sqlQuery(string $sql, array $bindings = [], float $time = 0): void
    {
        if (!app()->isDebug()) {
            return; // 非调试模式不记录SQL日志
        }

        $logData = [
            'sql' => $sql,
            'bindings' => $bindings,
            'time_ms' => $time,
        ];

        $level = $time > 100 ? 'warning' : 'debug'; // 超过100ms记录为警告
        self::structured('SQL查询', $logData, $level);
    }
}
